/*
 *  Gurr - A multiprotocol chat client for Android
 *  Copyright (C) 2011 Malte Aschermann, Wilfried Ramaker
 *  
 *  This file is part of Gurr.
 *  
 *  Gurr is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *  
 *  Gurr is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *  
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with Gurr.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.masc.gurr.model.xml;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.XMLOutputter;

import android.app.Activity;
import android.content.Context;
import android.os.Environment;
import android.provider.OpenableColumns;

import com.masc.gurr.model.Account;
import com.masc.gurr.model.AccountMap;
import com.masc.gurr.model.Contact;
import com.masc.gurr.model.Group;
import com.masc.gurr.model.History;
import com.masc.gurr.model.Message;
import com.masc.gurr.model.ProtocolType;
import com.masc.gurr.model.Session;
import com.masc.gurr.view.activities.AccountActivity;

public class Writer {

	public static final String SESSION_FILE_PREFIX="session_";
	
	private String getHistoryFName(String pStrUin) {
		return Reader.FILE_HISTORY_PREFIX + pStrUin + ".xml";
	}
	
	private String getContactsFName(String pStrUin) {
		return Reader.FILE_CONTACTS_PREFIX + pStrUin + ".xml";
	}
	
	private String getSessionFName(String pStrMyUin, long freeSid, String pStrBuddyUin) {
		return Writer.SESSION_FILE_PREFIX + pStrMyUin + "_" + freeSid + "_" + pStrBuddyUin + ".xml";
	}
	
	public void writeContactList(Account pAccount, ProtocolType pProtocolType,
			Group pGroupRoot, Activity parent) {
		if (pProtocolType == ProtocolType.ICQ) {
			writeContactListICQ(pAccount, pGroupRoot, parent);
		}
	}

	private void writeContactListICQ(Account pAccount, Group pGroupRoot, Activity parent) {
		
		if (pGroupRoot == null)
			return;

		Element root = new Element("contacts");
		Document doc = new Document(root);
		root.setAttribute("uin", pAccount.getUin());
		root.setAttribute("protocol", "ICQ");
		parseContactListICQ(pGroupRoot, root);

		try {
			FileOutputStream out = parent.openFileOutput(getContactsFName(pAccount.getUin()), Context.MODE_PRIVATE);
			XMLOutputter serializer = new XMLOutputter();
			serializer.output(doc, out);
			out.flush();
			out.close();
		}
		catch (IOException e) {
			System.err.println(e);
		}
	}

	private void parseContactListICQ(Group pGroupCurrent, Element pElementCurrent) {
		System.out.println("writer: found grp " + pGroupCurrent.getName() + " with groupId " + pGroupCurrent.getGid());
		Iterator<Contact> itc = pGroupCurrent.getContacts();
		while (itc.hasNext()) {
			Contact c = itc.next();
			System.out.println(" -> " + c.getName() + " (" + pGroupCurrent.getName() + ")");
			Element contact = new Element("contact");
			contact.setAttribute("uin", c.getUin());
			String name = c.getName();
			if (name == null)
				name = "";
			contact.setAttribute("name", name);
			String statusMsg = c.getStatusMsg();
			if (statusMsg == null)
				statusMsg = "";
			contact.setAttribute("statusmsg", statusMsg);
			pElementCurrent.addContent(contact);
		}

		Iterator<Group> itg = pGroupCurrent.getSubgroups();
		while (itg.hasNext()) {
			Group g = itg.next();
			Element group = new Element("group");
			if(g.getName()!= null)
				group.setAttribute("name", g.getName());
			else
				group.setAttribute("name", "");
			pElementCurrent.addContent(group);
			parseContactListICQ(g, group);
		}
	}

	protected void checkForHistory(String pStrMyUin, Activity parent) {
		
		 try {
			 /* test if history.xml already exists */
			for (String file : parent.fileList()) {
				if (file.equals(getHistoryFName(pStrMyUin))) {
					/* if uin in file matches pStrMyUin all good -> return */
					FileInputStream in = parent.openFileInput(getHistoryFName(pStrMyUin));
					SAXBuilder builder = new SAXBuilder();
					Document hdoc = builder.build(in);
					Element hroot = hdoc.getRootElement();
					if (hroot.getAttributeValue("uin").equals(pStrMyUin))
						return;
					else
						break;
				}
			}
			
			/* otherwise create new history */
			
			/* remove all session files */
			for (String file : parent.fileList()) {
				if (file.startsWith(SESSION_FILE_PREFIX))
					parent.deleteFile(file);
			}
			
			FileOutputStream hout = parent.openFileOutput(getHistoryFName(pStrMyUin), Context.MODE_PRIVATE);
			XMLOutputter serializer = new XMLOutputter();
			Element history = new Element("history");
			history.setAttribute("uin", pStrMyUin);
			history.setAttribute("freesid", "0");
			Document hdoc = new Document(history); 
			serializer.output(hdoc, hout);

			hout.flush();
			hout.close();
			
		} catch (IOException e) {
			e.printStackTrace();
		} catch (JDOMException e) {
			e.printStackTrace();
		}
	}

	/** STEP ONE:
	 * Read history.xml to get the next free sid and write references to new session files.
	 */
	private void writeHistoryFile(History pHistory, String pStrBuddyUin, Activity parent) {
		/* fail-safes: */
		if (pHistory==null)
			return;
		/* make sure history.xml exists */
		checkForHistory(pHistory.getMyUin(), parent);

		/* read history.xml to get next free sid (freesid) and 
		 * append new session references from pHistory to exisiting ones */
		SAXBuilder builder = new SAXBuilder();

		try {
			FileInputStream in = parent.openFileInput(getHistoryFName(pHistory.getMyUin()));
			Document hdoc = builder.build(in);
			Element hroot = hdoc.getRootElement();

			if (! hroot.getAttributeValue("uin").equals(pHistory.getMyUin()))
				return;

			long freeSid = Long.parseLong(hroot.getAttributeValue("freesid"));

			in.close();

			/* if pStrBuddyUin is null write all sessions, otherwise only those belonging to the buddy's uin 
			 * so we need to collect all sessions that needs to be written
			 */
			List<Session> lstSessions = new ArrayList<Session>();
			if (pStrBuddyUin==null) { /* all sessions */
				for (ArrayList<Session> s : pHistory.getBuddyUinSessionMap().values())
					lstSessions.addAll(s);
			} else { /* only buddy's sessions */ 
				if (pHistory.getBuddyUinSessionMap().get(pStrBuddyUin) != null)
					lstSessions.addAll(pHistory.getBuddyUinSessionMap().get(pStrBuddyUin));
			}
			
			/* append sessions to hroot */
			Iterator<Session> itS = lstSessions.iterator();
			while(itS.hasNext()) {
				Session s = itS.next();

				/* get sessions tag of buddy, if it doesn't exist, create one */
				Element elBuddySessions = null;
				List<Element> elSessions = hroot.getChildren("sessions");
				for (Element el : elSessions) {
					if (el.getAttributeValue("buddy").equals(s.getBuddyUin())) {
						elBuddySessions = el;
						break;
					}
				}
				if (elBuddySessions == null) { /* we did not find buddy's sessions tag, create it */
					elBuddySessions = new Element("sessions");
					elBuddySessions.setAttribute("buddy", s.getBuddyUin());
					hroot.addContent(elBuddySessions);
				}
				// Session file name
				String fileS = getSessionFName(pHistory.getMyUin(), freeSid, pStrBuddyUin);
		
				/* new reference to session file */
				Element elS = new Element("session");
				elS.setAttribute("file", fileS);
				elS.setAttribute("sid", String.valueOf(freeSid));
				elBuddySessions.addContent(elS);
				
				/* update pHistory->Session sid */
				s.setSid(freeSid);

				/* start step two: write the session file */
				writeSessionFile(s, freeSid, fileS, parent);

				/* next free sid */
				freeSid++;

			}
			
			/* remove written sessions from pHistory (buffer) */
			if (pStrBuddyUin==null)
				pHistory.removeAllSessions();
			else
				pHistory.removeAllSessions(pStrBuddyUin);

			/* update freesid attribute in history (root) tag */
			hroot.setAttribute("freesid", String.valueOf(freeSid));

			/* write new history.xml */
			FileOutputStream hout = parent.openFileOutput(getHistoryFName(pHistory.getMyUin()), Context.MODE_PRIVATE);
			XMLOutputter serializer = new XMLOutputter();
			serializer.output(hdoc, hout);
			hout.flush();
			hout.close();
			

		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (JDOMException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (NumberFormatException e) {
			e.printStackTrace();
		}

	}

	/** STEP TWO:
	 * Write session files
	 */
	private void writeSessionFile(Session pSession, long pLongSid, String fileS, Activity parent) {
		
		Document sdoc;
		Element sroot;
		
		try {

			/* build xml session structure */ 
			sroot = new Element("session");
			sdoc = new Document(sroot);

			sroot.setAttribute("sid", String.valueOf(pLongSid));
			sroot.setAttribute("buddy", pSession.getBuddyUin());
		
			Iterator<Message> itM = pSession.getMessageIterator();
			while (itM.hasNext()) {
				Message m = itM.next();
				
				Element elM = new Element("message");
				elM.setAttribute("date", String.valueOf(m.getDate().getTime()) );
				elM.setAttribute("sender", m.getSender());
				elM.setAttribute("id", String.valueOf(m.getMsgId()));
				elM.setText(m.getContent());
				sroot.addContent(elM);
			}

			/* write new session xml file */
			FileOutputStream sout = parent.openFileOutput(fileS, Context.MODE_PRIVATE);
			XMLOutputter serializer = new XMLOutputter();
			serializer.output(sdoc, sout);
			sout.flush();
			sout.close();
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (NumberFormatException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Just write specific buddy's history to xml 
	 * @param fBufferHistory
	 * @param pStrBuddyUin only write sessions w/ pStrBuddyUin's uin.
	 */
	public void writeHistory(History pBufferHistory, String pStrBuddyUin, Activity parent) {
		writeHistoryFile(pBufferHistory, pStrBuddyUin, parent);
	}
	
	/**
	 * Write history to xml 
	 * @param fBufferHistory
	 */
	public void writeHistory(History pBufferHistory, Activity parent) {
		writeHistoryFile(pBufferHistory, null, parent);
	}

	public void writeAccounts(AccountMap pMapUinMyAccounts,	Activity parent) {
		writeAccountsFile(pMapUinMyAccounts, parent);
	}

	private void writeAccountsFile(AccountMap pMapUinMyAccounts, Activity parent) {
		if (pMapUinMyAccounts == null)
			return;

		Element root = new Element("accounts");
		Document doc = new Document(root);
		Iterator<Account> itc = pMapUinMyAccounts.getAllAccounts();
		while (itc.hasNext()) {
			Account account = (Account) itc.next();
			Element elA = new Element("account");
			
			elA.setAttribute("type", String.valueOf(account.getType().ordinal()));
			elA.setAttribute("uin", account.getUin());
			elA.setAttribute("pass", account.getPass());
			elA.setAttribute("alias", account.getAlias());
			root.addContent(elA);
		}
		
		try {
			FileOutputStream out = parent.openFileOutput(Reader.FILE_ACCOUNTS, Context.MODE_PRIVATE);
			XMLOutputter serializer = new XMLOutputter();
			serializer.output(doc, out);
			out.flush();
			out.close();
		}
		catch (IOException e) {
			System.err.println(e);
		}
	}

}
